package DAL
{
	
	import GUI.*;
	
	import MUNDO.Jugador;
	import MUNDO.Partida;
	
	import flash.display.Stage;
	import flash.events.TimerEvent;
	import flash.geom.Utils3D;
	import flash.utils.Timer;
	
	import playerio.Client;
	import playerio.Connection;
	import playerio.DatabaseObject;
	import playerio.Message;
	import playerio.PlayerIO;
	import playerio.PlayerIOError;
	
	import sample.ui.Lobby;
	import sample.ui.components.Chat;
	
	public class Conexion
	{
		private var _triviador:Triviador = null;
		private var _connection:Connection;
		private var _preguntaCerrada:Boolean = false;
		private var mapa:Mapa;
		private var reloj4seg:Timer;
		
		public function get connection():Connection
		{
			return _connection;
		}
		public function Conexion(triviador:Triviador)
		{
			_triviador = triviador;
		}
		
		/**
		 * Se establece una conexion con el servidor de PLAYERIO como usuario "SU".
		 */
		public function conectarSU():void{
			PlayerIO.connect(
				_triviador.stage,							//Referance to stage
				"triviador-zh6t1rvdteo5wgqxlzm3q",			//Game id
				"public",									//Connection id, default is public
				"SUDO",										//Username
				"",											//User auth. Can be left blank if authentication is disabled on connection
				null,										//Current PartnerPay partner.
				handleConnectSU,							//Function executed on successful connect
				handleError									//Function executed if we recive an error
			);  
		}
		
		/**
		 * Esta funcion establece la conexion con el servidor en una sesión de super usuario ("SU")
		 * @param client Cliente ficticio que desea conectarse al servidor como root. 
		 */
		private function handleConnectSU(client:Client):void{
			Partida.client = client;
			trace("Sucessfully connected to player.io to " + Partida.ip + ":8184");
			//Set developmentsever (Comment out to connect to your server online)
			Partida.client.multiplayer.developmentServer = Partida.ip + ":8184";
		}
		
		/**
		 * Se establece una conexion con el servidor de PLAYERIO.
		 */
		public function conectar():void
		{
			PlayerIO.connect(
				_triviador.stage,							//Referance to stage
				"triviador-zh6t1rvdteo5wgqxlzm3q",			//Game id
				"public",									//Connection id, default is public
				Partida.jugador.nombre,						//Username
				"",											//User auth. Can be left blank if authentication is disabled on connection
				null,										//Current PartnerPay partner.
				handleConnect,								//Function executed on successful connect
				handleError									//Function executed if we recive an error
			);  
		}
		
		/**
		 * Esta funcion establece la conexion con el servidor, le indica al servidor
		 * el nombre del jugador y muestra el lobby.
		 * @param client El cliente que desea conectarse al servidor. 
		 */
		private function handleConnect(client:Client):void
		{
			trace("handleConnect");

			Partida.client = client;
			_triviador.gotoAndStop(2);
			trace("Sucessfully connected to player.io");
			//Set developmentsever (Comment out to connect to your server online)
			Partida.client.multiplayer.developmentServer = Partida.ip + ":8184";
			//Create lobby
			var lobby:Lobby = new Lobby( _triviador, Partida.client, "Triviador", handleJoin, handleError);
			//Show lobby (parsing true hides the cancel button)
			lobby.show(true);
			_triviador.gotoAndStop(2);
		}
		
		/** Esta funcion se ejecuta cuando halla un error en la conexion,
		 * al haber un error en la conexion se redirige al usuario a iniciar sesion nuevamente
		 * @param error Error que ha arrojado la conexion 
		 */
		private function handleError(error:PlayerIOError):void{
			trace("got",error)
			_triviador.gotoAndStop(1,"Escena 1");
			var login:Login = new Login(_triviador);
			login.mostrarLogin();
		}
		/**
		 *  El usuario ha ingresado a una partida, esta partida tiene una conexión en especifico a la que
		 * hay que añadirle todos los posibles mensajes que puede enviar el servidor para que al ser recibido
		 * cada mensaje el cliente sepa que hacer.
		 * @param connection Es la conexion de la partida que debe ser igualada a la conexion del cliente
		 */
		private function handleJoin(connection:Connection):void{
			trace("Sucessfully connected to the multiplayer server");
			//Add connection to actual connection
			mapa = new Mapa(_triviador);
			_connection = connection;
			connection.send("MyNameIs",Partida.jugador.nombre);
			_triviador.gotoAndStop(3,"Escena 7");
			var chat:Chat = new Chat(_triviador.stage , _connection);
			_triviador.addChild(chat);
			
			//Add disconnect listener
			connection.addDisconnectHandler(handleDisconnect);
			
			//Add listener for messages of the type "hello"
			connection.addMessageHandler("Nombres", function(m:Message,nombreJ1:String, nombreJ2:String, nombreJ3:String):void {
				trace("Recived a message with the type Nombres from the server");
				
				_triviador.gotoAndStop(1,"Escena 13");
				mapa = new Mapa(_triviador);
				Partida.nombre1 = nombreJ1;
				Partida.nombre2 = nombreJ2;
				Partida.nombre3 = nombreJ3;
				mapa.mostrarNombres(nombreJ1, nombreJ2, nombreJ3);
				var mapaInicioTemp:Timer = new Timer(5000);
				mapaInicioTemp.addEventListener(TimerEvent.TIMER, esperarASeleccionBasesEvent);
				mapaInicioTemp.start();
				
				function esperarASeleccionBasesEvent(e:TimerEvent):void
				{
					_triviador.stop();
					mapaInicioTemp.stop();
					mapaInicioTemp.reset();
					mapa.asignandoBases();
					//mapa.seleccionBases();
				}
			})
			
			/**
			 * Funcion que obtiene los id de cada jugador previamente logueado, y dados estos, asigna de forma aleatoria
			 * las coordenadas para cada base.
			 **/	
			connection.addMessageHandler("jugadoresCompletos", function(m:Message, b1:int, b2:int, b3:int, id:int):void {
				UtilsDAO.cargarTerritoriosOcupados();
				Partida.jugador.id = id;
				Partida.jugador.puntaje = 1000;
				trace("ESTE ES EL ID: " + Partida.jugador.id);
				Partida.territorioOcupado[b1]  =true;
				Partida.territorioOcupado[b2]  =true;
				Partida.territorioOcupado[b3]  =true;
				if (id == 1)
				{
					Partida.jugador.base = b1;
				}
				if (id == 2)
				{
					Partida.jugador.base = b2;
				}
				if (id == 3)
				{
					Partida.jugador.base = b3;
				}
				Partida.base1 = new Base1();
				Partida.base2 = new Base2();
				Partida.base3 = new Base3();
				var territorio:TerritorioDAO = new TerritorioDAO();
				UtilsDAO.cargarPuntos(Partida.jugador.nombre, 1000);
				
				territorio.cargarCoordenadasenXb1(b1);
				territorio.cargarCoordenadasenYb1(b1);
				territorio.cargarCoordenadasenXb2(b2);
				territorio.cargarCoordenadasenYb2(b2);
				territorio.cargarCoordenadasenXb3(b3);
				territorio.cargarCoordenadasenYb3(b3);
				trace("Recived a message with the type jugadoresCompletos from the server");
			})
			
			//Add message listener for users joining the room
			connection.addMessageHandler("UserJoined", function(m:Message, userid:uint):void {
				trace("Player with the userid", userid, "just joined the room");
			})
			
			//Para que esto?????????
			connection.addMessageHandler("TerritorioSeleccionado", function(m:Message, userid:uint, territorio:int):void {
			})
			
			/*connection.addMessageHandler("Restart", function(m:Message):void {
				redireccionar.addEventListener(TimerEvent.TIMER_COMPLETE, redireccionarComplete);
				redireccionar.start();
			})*/
			
			
			//Add message listener for users leaving the room
			connection.addMessageHandler("UserLeft", function(m:Message, userid:uint):void {
				trace("Player with the userid", userid, "just left the room");
			})
			
			connection.addMessageHandler("DibujarTerritorio", function(m:Message, territorio:uint, userid:uint):void {
				mapa.dibujarAstronauta(territorio,userid);
			})	
				
				
			connection.addMessageHandler("OrdenEleccion", function(m:Message, u1:int,u2:int,u3:int):void {
				trace ("Orden eleccion: "+u1+" "+u2+" "+u3);
				trace ("ID mio: "+Partida.jugador.id);
				if (u1 == Partida.jugador.id)
				{
					trace ("Inicio a escoger yo");
					mapa.mostrarTerritoriosParaEscoger();
				}
				else
				{
					_triviador.gotoAndStop(1,"Escena 13");
				}
			})
			
			//Add message listener for users leaving the CHAT 
			connection.addMessageHandler("ChatLeft", function(m:Message, userid:uint):void {
				trace("Player with the userid", userid, "just left the chat");
			})
			
			//Listen to all messages using a private function
			connection.addMessageHandler("*", handleMessages);
			
			connection.addMessageHandler("preguntaAbierta", function(m:Message, numero:int):void {
				trace("Recived a message with the type PREGUNTA ABIERTA from the server: "+numero);
				var timer15Seg:Timer = new Timer(1000, 15);
				_preguntaCerrada = false;
				timer15Seg.addEventListener(TimerEvent.TIMER_COMPLETE, onTimerComplete);
				//Inicio del contador
				timer15Seg.reset();
				timer15Seg.start();
				_triviador.stop();
				var preguntaAbierta:PreguntaAbierta = new PreguntaAbierta(_triviador, timer15Seg, numero);
				preguntaAbierta.MostrarPreguntaAbierta(Number(numero));
			})
			
			connection.addMessageHandler("preguntaCerrada", function(m:Message, numero:int):void {
				trace("Recived a message with the type PREGUNTA CERRADA from the server");
				var timer15Seg:Timer = new Timer(1000, 15);
				_preguntaCerrada = true;
				//Inicio del contador
				timer15Seg.reset();
				timer15Seg.start();
				_triviador.stop();
				var preguntaCerrada:PreguntaCerrada = new PreguntaCerrada(_triviador, timer15Seg);
				preguntaCerrada.MostrarPreguntaCerrada(Number(numero));
			})
			
			connection.addMessageHandler("Win", function(m:Message, numero:int):void {
				trace("Recived a message with the type WIN from the server");
				
				if (numero == 1)
				{
					reloj4seg = new Timer(1000,4);
					reloj4seg.addEventListener(TimerEvent.TIMER_COMPLETE,timerComplete);
					reloj4seg.start();
					UtilsDAO.cargarPuntos(Partida.jugador.nombre,200);
					_triviador.gotoAndStop(5, "Escena 7");
					
				}
				if (numero == 2)
				{
					reloj4seg = new Timer(1000,4);
					reloj4seg.addEventListener(TimerEvent.TIMER_COMPLETE,timerComplete);
					reloj4seg.start();
					UtilsDAO.cargarPuntos(Partida.jugador.nombre,400);
					_triviador.gotoAndStop(2, "Escena 7");
				}

			})
			
			connection.addMessageHandler("Lose", function(m:Message):void {
				trace("Recived a message with the type LOSE from the server");
				reloj4seg = new Timer(1000,4);
				reloj4seg.addEventListener(TimerEvent.TIMER_COMPLETE,timerComplete);
				reloj4seg.start();
				_triviador.gotoAndStop(4, "Escena 7");
			})
			
			connection.addMessageHandler("deleteChat", function(m:Message):void {
				trace("Deleting chat...");
				_triviador.removeChild(chat);
			})
		}
		private function timerComplete(e:TimerEvent){
			reloj4seg.stop();
			reloj4seg.reset();
			mapa.cargarImagenes();
		}
		/** Esta funcion le indica al cliente que se ha desconectado del servidor
		 * y lo indica mediante un mensaje por consola si se esta ejecutando el cliente en flash professional
		 */
		private function handleDisconnect():void{
			trace("Disconnected from server")
			if (!Partida.solicitoDesconexion)
			{
				conectar();
			}
		}
		
		/**
		 * La funcion indica al servidor que al usuario se le ha agotado el tiempo, por tanto ha perdido y 
		 * se lo notifica al servidor y al usuario.
		 * @param event Evento que indica que el tirmpo que tiene el usuario se ha acabado
		 */
		public function onTimerComplete(event:TimerEvent):void 
		{ 
			trace("Time's Up!");
			
			if (_preguntaCerrada)
			{
				enviarPerderCerradas();
				trace("Tiempo agotado PREGUNTA CERRADA");
			}
			else
			{
				enviarPerderAbiertas();
				trace("Tiempo agotado PREGUNTA ABIERTA");
			}
			//_triviador.gotoAndStop(1,"Escena 7");
			_preguntaCerrada = false;
		}
		
		/**
		 * Funcion que imprime el mensaje que se ha recibido. (unicamente lo imprime si se esta ejecutando
		 * el cliente en flash professional.
		 * @param m Mensaje de tipo Mensaje que se quiere imprimir
		 */
		private function handleMessages(m:Message):void {
			trace("Recived the message", m)
		}
		
		/**Funcion que envia al servidor que el usuario ha respondido mal la pregunta cerrada
		 */
		public function enviarPerderCerradas():void
		{
			_connection.send("LosePregCerradas");
		}
		
		/**
		 * Funcion que envia al servidor que el cliente ha perdido por tiempo. 
		 */
		public function enviarPerderAbiertas():void
		{
			_connection.send("Lose",100000000);
		}


	}
}